package study.web.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

import study.domain.Constants;
import study.domain.user.User;
import study.service.user.UserService;

/**
 * Spring Security의 RememberMe를 통해서 인증된 경우 세션에 사용자 정보를 넣어준다.
 *
 * @author Barney
 */
public class UserRememberMeFilter extends GenericFilterBean {

	@Autowired
	private UserService userService;

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@Override
	public void afterPropertiesSet() {
		Assert.notNull(userService, "userService must be specified");
	}

	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if(auth != null) {
			if(auth instanceof RememberMeAuthenticationToken) {
				HttpSession session = request.getSession();
				User user = (User)session.getAttribute(Constants.SESSION_KEY);
				if(user == null) {
					String username = getUsername(auth);
					user = userService.getUser(username);
					if(user != null) {
						logger.debug("User '"+username+"' into session");
						session.setAttribute(Constants.SESSION_KEY, user);
					} else{
						logger.error("User '"+username+"' NOT FOUND");
					}
				}
			}
		}
		chain.doFilter(req, res);
	}

	private String getUsername(Authentication authentication) {
		Object principal = authentication.getPrincipal();
		if (principal instanceof UserDetails) {
			return ((UserDetails) principal).getUsername();
		} else {
			return principal.toString();
		}
	}
}
